//
// Copyright (C) [2024] Xingyun Integrated Circuit, Inc.
//
// GreenCode was a private technology asset of Xingyun Integrated Circuit， Inc （Confidential）
//  Author: Shawn.Tan
//  Date : 2025.10.28
//
//  History : Initial Version 2025.10.28
//

//
#include "PageRequestRegulatorGPGPU.h"

#include "GenRequest.h"
#include "Generator.h"
#include "InstructionStructure.h"
#include "Log.h"
#include "Register.h"

using namespace std;

/*!
  \file PageRequestRegulatorGPGPU.cc
  \brief GPGPU layer paging request regulating code.
*/

namespace Green {

  Object* PageRequestRegulatorGPGPU::Clone() const
  {
    return new PageRequestRegulatorGPGPU(*this);
  }

  PageRequestRegulatorGPGPU::PageRequestRegulatorGPGPU()
    : PageRequestRegulator()
  {
    //mInstrExceptionTypes.push_back(EPagingExceptionType::InstructionAccessFault);
    mInstrExceptionTypes.push_back(EPagingExceptionType::InstructionPageFault);

    //mDataExceptionTypes.push_back(EPagingExceptionType::LoadAccessFault);
    //mDataExceptionTypes.push_back(EPagingExceptionType::StoreAmoAccessFault);
    mDataExceptionTypes.push_back(EPagingExceptionType::LoadPageFault);
    mDataExceptionTypes.push_back(EPagingExceptionType::StoreAmoPageFault);
  }

  PageRequestRegulatorGPGPU::PageRequestRegulatorGPGPU(const PageRequestRegulatorGPGPU& rOther)
    : PageRequestRegulator(rOther)
  {

  }

  PageRequestRegulatorGPGPU::~PageRequestRegulatorGPGPU()
  {

  }

  void PageRequestRegulatorGPGPU::Setup(const Generator* pGen)
  {
    PageRequestRegulator::Setup(pGen);
  }

  void PageRequestRegulatorGPGPU::RegulateLoadStorePageRequest(const VmMapper* pVmMapper, const LoadStoreOperandStructure* pLsStruct, GenPageRequest* pPageReq) const
  {
    uint32 priv_level = mpGenerator->PrivilegeLevel();
    if (nullptr != pLsStruct)
    {
      // coming from instruction, can use current privilege level
      if (pLsStruct->Unprivileged() || priv_level == 0)
      {
        pPageReq->SetPrivilegeLevel(EPrivilegeLevelType::U);
      }
      else
      {
        pPageReq->SetGenBoolAttribute(EPageGenBoolAttrType::Privileged, 1);
      }

      if (pLsStruct->AtomicOrderedAccess())
      {
        pPageReq->SetGenBoolAttribute(EPageGenBoolAttrType::Atomic, 1);
      }
    }
    else
    {
      // not coming from instruction, therefore targetting EL might be reached via exception.
      if (pPageReq->PrivilegeLevelSpecified())
      {
        priv_level = uint32(pPageReq->PrivilegeLevel());
      }
      else if (priv_level == 0)
      {
        pPageReq->SetPrivilegeLevel(EPrivilegeLevelType::U);
      }

      if (priv_level != 0)
      {
        pPageReq->SetGenBoolAttribute(EPageGenBoolAttrType::Privileged, 1);
      }
    }

    PageRequestRegulator::RegulateLoadStorePageRequest(pVmMapper, pLsStruct, pPageReq);
  }

  void PageRequestRegulatorGPGPU::RegulateBranchPageRequest(const VmMapper* pVmMapper, const BranchOperandStructure* pBrStruct, GenPageRequest* pPageReq) const
  {
    uint32 priv_level = mpGenerator->PrivilegeLevel();
    if (nullptr != pBrStruct)
    {
      // coming from instruction, can use current privilege level
      if (priv_level == 0)
      {
        pPageReq->SetPrivilegeLevel(EPrivilegeLevelType::U);
      }
      else
      {
        pPageReq->SetGenBoolAttribute(EPageGenBoolAttrType::Privileged, 1);
      }
    }
    else
    {
      // not coming from instruction, so target privilege could differ from the current privilege.
      if (pPageReq->PrivilegeLevelSpecified())
      {
        priv_level = uint32(pPageReq->PrivilegeLevel());
      }
      else if (priv_level == 0)
      {
        pPageReq->SetPrivilegeLevel(EPrivilegeLevelType::U);
      }

      if (priv_level != 0)
      {
        pPageReq->SetGenBoolAttribute(EPageGenBoolAttrType::Privileged, 1);
      }
    }

    PageRequestRegulator::RegulateBranchPageRequest(pVmMapper, pBrStruct, pPageReq);
  }

}
